﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace ADiKt {
    abstract class Worm {
        public float angle;
        public string colourName;
        public Color colour;
        protected float length = Globals.segment_length;
        public Boolean alive = true;
        public double score = 0;
        protected Vector2 pos;
        public List<Vector2> body = new List<Vector2>();
        public List<RoundLine> bodyLines = new List<RoundLine>();

        abstract public void turn(KeyboardState ks);

        public void update(KeyboardState ks) {
            turn(ks);
            pos += new Vector2((float)(length * Math.Cos(angle)), (float)(length * Math.Sin(angle)));

            if (collision(body.Last(), pos)) {
                Game1.crashSound.Play();
                alive = false;
            } else {
                bodyLines.Add(new RoundLine(body.Last(), pos));
                Globals.points[(int)((double)Globals.gridSize * pos.X / (double)Globals.width), (int)((double)Globals.gridSize * pos.Y / (double)Globals.height)].Add(bodyLines.Last());
                body.Add(pos);

                score += 0.05;

                //chance to create a gap
                //TODO - gap cooldown
                //TODO - fix gap bug (missaligned??)
                if (Globals.rand.NextDouble() < Globals.gap_chance && bodyLines.Count() >= Globals.gap_size) {
                    for (int i = 1; i <= Globals.gap_size; i++) {
                        int x = (int)((double)Globals.gridSize * bodyLines.Last().P0.X / (double)Globals.width);
                        int y = (int)((double)Globals.gridSize * bodyLines.Last().P0.Y / (double)Globals.height);
                        Globals.points[x, y].Remove(bodyLines.Last());
                        bodyLines.Remove(bodyLines.Last());
                    }
                }
            }
        }


        protected Boolean collision(Vector2 start, Vector2 end) {
            if (pos.X < 0 || pos.X > Globals.width || pos.Y < 0 || pos.Y > Globals.height) {
                return true;
            }

            List<RoundLine> rls = new  List<RoundLine>();
            int x= (int)((double)Globals.gridSize * pos.X / (double)Globals.width);
            int y = (int)((double)Globals.gridSize * pos.Y / (double)Globals.height);
            for (int i = -1; i <= 1; i++) {
                for (int j = -1; j <= 1; j++) {
                    if (x + i > -1 && x + i < Globals.gridSize && y + j > -1 && y + j < Globals.gridSize)
                        rls.AddRange(Globals.points[x + i, y + j]);
                }
            }
            foreach (RoundLine rl in rls) {
                if (rl.doLinesIntersect(start, end)) {
                    if (rl.P1 != start) {
                        return true;
                    }
                }
            }
            return false;
        }

        //reset fields for next round
        public void reset() {
            int x = Globals.rand.Next((int)(Globals.width * 0.5)) + (int)(Globals.width * 0.25);
            int y = Globals.rand.Next((int)(Globals.height * 0.5)) + (int)(Globals.height * 0.25);
            pos = new Vector2(x, y);
            angle = (float)(Globals.rand.NextDouble() * 2.0 * Math.PI);
            alive = true;
            body.Clear();
            bodyLines.Clear();
            body.Add(new Vector2(x, y));
        }

        //remove a line
        public void delete() {
            Globals.colListFree.Add(colour, colourName);
            Globals.colListUsed.Remove(colour);
            Globals.worms.Remove(this);
        }

        //change colour
        public void changeColour(Color col) {
            Globals.colListFree.Add(colour, colourName);
            Globals.colListUsed.Remove(colour);
            this.colour = col;
            this.colourName = Globals.colListFree[col];
            Globals.colListUsed.Add(col, colourName);
            Globals.colListFree.Remove(col);
        }
    }
}
